// ===TS内置工具类型===
//  Partial<T>  将一个类型的所有属性变为可选的.
//  Required<T> 将给定类型的所有属性变为必填的.
//  Readonly<T> 将给定类型的所有属性设为只读，这意味着给定类型的属性不可以被重新赋值。
//  Pick<T,'name' | 'age' | 'id'> 从给定的类型中选取出指定的键值，然后组成一个新的类型。
//  Omit<T,'name' | 'age' | 'id'> 是返回去除指定的键值之后返回的新类型
//  Record<string,any> Record 的作用是生成接口类型，然后我们使用传入的泛型参数分别作为接口类型的属性和值。
//  null  document.body!.style 非空判断
//  Exclude<T, U>  从 T 泛型类型 中过滤掉 U 的类型
//  Extract<T, U>  从泛型T U中获取相交的类型
// NonNullable：从联合类型中去除 null 或者 undefined 的类型
// ReturnType 的作用是用来获取函数的返回类型
// Parameters<T>  获取函数的参数类型

import { keyOf } from 'core-js/core/dict';

// 转换字符串字面量到大写字母
// type Uppercase<S extends string> = intrinsic;
// // 转换字符串字面量到小写字母
// type Lowercase<S extends string> = intrinsic;
// // 转换字符串字面量的第一个字母为大写字母
// type Capitalize<S extends string> = intrinsic;
// // 转换字符串字面量的第一个字母为小写字母
// type Uncapitalize<S extends string> = intrinsic;
// type T0 = Uppercase<'Hello'>; // => 'HELLO'
// type T1 = Lowercase<T0>; // => 'hello'
// type T2 = Capitalize<T1>; // => 'Hello'
// type T3 = Uncapitalize<T2>; // => 'hello'

// infer R 利用ts的推断类型

// keyof typeof 模版字符串

//=======================================
/**将一个对象中的某些key变为可选 */
declare type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

// Awaited<T> = T extends Promise<infer R> ? R : T;

type Details = {
  name: string;
  age: number;
  adress: string;
  date: Date;
};

type Detail = Optional<Details, 'adress' | 'date'>;

//=======================================
/**从字段到函数的推导 */
type Watch<T> = {
  on<K extends string & keyof T>(eventName: `${K}Change`, callBack: (oldVal: T[K], newVal: T[K]) => void): void;
};
declare function watch<T>(obj: T): Watch<T>;
const personWatch = watch({
  firstName: 'llq',
  lastName: 'me',
  age: 25,
});
personWatch.on('firstNameChange', (oldVal, newVal) => {});
personWatch.on('ageChange', (oldVal, newVal) => {});
//=======================================

type Add = (a: number, b: number) => number;
const add: Add = function (a: number, b: number) {
  return a + b;
};
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : T;
let sumRes: ReturnType<Add>;

type ArrayItemType<T> = T extends (infer I)[] ? I : T;
type item1 = ArrayItemType<[string, number]>;

/**
 * Make all properties in T optional
 */
type Partial<T> = {
  [P in keyof T]?: T[P];
};

/**
 * Make all properties in T required
 */
type Required<T> = {
  [P in keyof T]-?: T[P];
};

/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
  [P in K]: T;
};

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T & {};

/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

/**
 * Obtain the parameters of a constructor function type in a tuple
 */
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (
  ...args: infer P
) => any
  ? P
  : never;

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

/**
 * Obtain the return type of a constructor function type
 */
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R
  ? R
  : any;

/**
 * Convert string literal type to uppercase
 */
type Uppercase<S extends string> = intrinsic;

/**
 * Convert string literal type to lowercase
 */
type Lowercase<S extends string> = intrinsic;

/**
 * Convert first character of string literal type to uppercase
 */
type Capitalize<S extends string> = intrinsic;

/**
 * Convert first character of string literal type to lowercase
 */
type Uncapitalize<S extends string> = intrinsic;

const arrT = ['a', 'b', 'c', 2] as const;
const arrU = {
  name: 'llq',
  age: 26,
};

type ARRT = (typeof arrT)[number];
type ARRU = keyof typeof arrU;

function foo<T extends { name: string }>(x: T): T['name'] {
  return x.name;
}

foo<{ name: string }>({ name: 'llq' });

type TyPEA = {
  name: string;
  age: number;
};
